package cz.muni.fi.pa165.bookingmanager.services.impl;

import cz.muni.fi.pa165.bookingmanager.dao.RoomManager;
import cz.muni.fi.pa165.bookingmanager.entities.Hotel;
import cz.muni.fi.pa165.bookingmanager.entities.Room;
import cz.muni.fi.pa165.bookingmanager.exceptions.IllegalOrphanException;
import cz.muni.fi.pa165.bookingmanager.exceptions.NonexistentEntityException;
import cz.muni.fi.pa165.bookingmanager.exceptions.PreexistingEntityException;
import cz.muni.fi.pa165.bookingmanager.interceptors.LoggingInterceptor;
import cz.muni.fi.pa165.bookingmanager.interceptors.ShiroSecuredInterceptor;
import cz.muni.fi.pa165.bookingmanager.services.RoomService;
import java.math.BigDecimal;
import java.util.List;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import org.apache.shiro.authz.annotation.RequiresRoles;

/**
 *
 * @author Jiří Holuša
 */
@Stateless
public class RoomServiceImpl implements RoomService {

    @EJB
    private RoomManager roomManager;
    @Resource
    private SessionContext ctx;

    @Override
    @Interceptors({ShiroSecuredInterceptor.class, LoggingInterceptor.class})
    @RequiresRoles("admin")
    public void createRoom(Room room) throws IllegalOrphanException, PreexistingEntityException {
        if (!isValidEntity(room)) {
            throw new IllegalArgumentException("Invalid Room entity.");
        }

        try {
            roomManager.createRoom(room);
        } catch (Exception ex) {
            ctx.setRollbackOnly();
        }
    }

    @Override
    @Interceptors({ShiroSecuredInterceptor.class, LoggingInterceptor.class})
    @RequiresRoles("admin")
    public void updateRoom(Room room) throws IllegalOrphanException, NonexistentEntityException {
        if (!isValidEntity(room)) {
            throw new IllegalArgumentException("Invalid Room entity.");
        }

        try {
            roomManager.updateRoom(room);
        } catch (Exception ex) {
            ctx.setRollbackOnly();
        }
    }

    @Override
    @Interceptors({ShiroSecuredInterceptor.class, LoggingInterceptor.class})
    @RequiresRoles("admin")
    public void deleteRoom(Room room) throws IllegalOrphanException, NonexistentEntityException {
        try {
            roomManager.deleteRoom(room);
        } catch (Exception ex) {
            ctx.setRollbackOnly();
        }
    }

    @Override
    @Interceptors(LoggingInterceptor.class)
    public Room getRoomById(Long id) {
        return roomManager.getRoomById(id);
    }

    @Override
    @Interceptors(LoggingInterceptor.class)
    public Room findRoomByNumber(String number, Hotel hotel) {
        return roomManager.findRoomByNumber(number, hotel.getId());
    }

    @Override
    @Interceptors(LoggingInterceptor.class)
    public List<Room> findAllHotelRooms(Hotel hotel) {
        List<Room> rooms = roomManager.findAllHotelRooms(hotel.getId());

        return rooms;
    }

    @Override
    @Interceptors(LoggingInterceptor.class)
    public List<Room> findRoomsByPrice(BigDecimal from, BigDecimal to) {
        List<Room> rooms = roomManager.findRoomsByPrice(from, to);

        return rooms;
    }

    @Override
    @Interceptors(LoggingInterceptor.class)
    public List<Room> findRoomsByPrice(BigDecimal from, BigDecimal to, Hotel hotel) {
        List<Room> rooms = roomManager.findRoomsByPrice(from, to, hotel.getId());

        return rooms;
    }

    @Override
    @Interceptors(LoggingInterceptor.class)
    public List<Room> findRoomsByCapacity(int capacity) {
        List<Room> rooms = roomManager.findRoomsByCapacity(capacity);

        return rooms;
    }

    @Override
    @Interceptors(LoggingInterceptor.class)
    public List<Room> findRoomsByCapacity(int capacity, Hotel hotel) {
        List<Room> rooms = roomManager.findRoomsByCapacity(capacity, hotel.getId());

        return rooms;
    }

    /**
     * Helper method for validation Room entity
     *
     * @param room
     * @return true if valid, otherwise false
     */
    private boolean isValidEntity(Room room) {
        if (room == null) {
            return false;
        }

        if (room.getRoomNumber() == null) {
            return false;
        }

        if (room.getPrice() == null || room.getPrice().compareTo(BigDecimal.ZERO) < 0) {
            return false;
        }

        if (room.getHotel() == null || room.getHotel().getId() == null) {
            return false;
        }

        if (room.getCapacity() <= 0) {
            return false;
        }

        return true;
    }

    public void setRoomManager(RoomManager roomManager) {
        this.roomManager = roomManager;
    }
}
